#include "gameInterface.hpp"
#include <cstdlib>
#include <ctime>

#include <iostream>
using namespace std;

//------------private functions------------
void GameInterface::createSquare(GLfloat x, GLfloat y, GLfloat z, GLfloat size, GLfloat *result){
    GLfloat halfSize = size/2;

    result[0] = x + halfSize;
    result[1] = y + halfSize;
    result[2] = z;

    result[3] = x - halfSize;
    result[4] = y + halfSize;
    result[5] = z;

    result[6] = x - halfSize;
    result[7] = y - halfSize;
    result[8] = z;


    result[9] = x + halfSize;
    result[10] = y + halfSize;
    result[11] = z;

    result[12] = x + halfSize;
    result[13] = y - halfSize;
    result[14] = z;

    result[15] = x - halfSize;
    result[16] = y - halfSize;
    result[17] = z;
}

void GameInterface::randColors(){
    for(int i = 0; i < (game->getColors() * 3); i++) {
            colorsTab[i] = (GLfloat)rand()/(GLfloat)RAND_MAX;
    }
}

void GameInterface::reserveMemory(){
    colorsTab = new GLfloat[game->getColors() * 3];

    int viewSize = ( game->getFields() * game->getRounds() * 2 + game->getFields() ) * 18 + 6;
    view = new GLfloat[viewSize];
    viewColors = new GLfloat[viewSize];

    checkBox = new int[game->getFields()];
    for(int i = 0; i < game->getFields(); i++){
        checkBox[i] = 0;
    }
}

void GameInterface::createCheckBox(){
    int fields = game->getFields();

    GLfloat *square = new GLfloat[18];

    float start = -1.0 + squareSpace/2.0 + squareSize/2.0;

    for(int i = 0; i < fields; i++){
        if(selection == i) createSquare(start + squareSpace * i, start, 0, selectionSize, square);
        else createSquare(start + squareSpace * i, start, 0, squareSize, square);

        for(int j = 0, k = 0; j < 18; j++, k++){
            if(k > 2) k = 0;
            view[i*18 + j] = square[j];
            viewColors[i*18 + j] = colorsTab[ k + 3 * checkBox[i] ];
        }
    }
}

void GameInterface::createPlayerWin(){
    cout << "win" << endl;

    trianglesNum = viewEnd/3;

    GLfloat *square = new GLfloat[18];

    createSquare(0, 0, -0.01, 0.7, square);

    for(int j = 0; j < 18; j++){
        view[viewEnd + j] = square[j];
        viewColors[viewEnd + j] = 0;
    }
    viewEnd += 18;

    createSquare(0.2, 0.1, -0.02, 0.2, square);

    for(int j = 0; j < 18; j++){
        view[viewEnd + j] = square[j];
        viewColors[viewEnd + j] = 1;
    }
    viewEnd += 18;

    createSquare(-0.2, 0.1, -0.02, 0.2, square);

    for(int j = 0; j < 18; j++){
        view[viewEnd + j] = square[j];
        viewColors[viewEnd + j] = 1;
    }
    viewEnd += 18;

    winTrianglesNum = 18;

    viewColors[viewEnd] = 1; view[viewEnd] =  -0.20; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] =  -0.1; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] = -0.02; viewEnd++;

    viewColors[viewEnd] = 1; view[viewEnd] =  -0.10; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] =  -0.2; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] = -0.02; viewEnd++;

    viewColors[viewEnd] = 1; view[viewEnd] =  0.10; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] =  -0.2; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] = -0.02; viewEnd++;

    viewColors[viewEnd] = 1; view[viewEnd] =  0.20; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] =  -0.1; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] = -0.02; viewEnd++;

    lineStripNum = 4;
}

void GameInterface::createPlayerLoose(){
    cout << "loose" << endl;

    trianglesNum = viewEnd/3;

    GLfloat *square = new GLfloat[18];

    createSquare(0, 0, -0.01, 0.7, square);

    for(int j = 0; j < 18; j++){
        view[viewEnd + j] = square[j];
        viewColors[viewEnd + j] = 0;
    }
    viewEnd += 18;

    createSquare(0.2, 0.1, -0.02, 0.2, square);

    for(int j = 0; j < 18; j++){
        view[viewEnd + j] = square[j];
        viewColors[viewEnd + j] = 1;
    }
    viewEnd += 18;

    createSquare(-0.2, 0.1, -0.02, 0.2, square);

    for(int j = 0; j < 18; j++){
        view[viewEnd + j] = square[j];
        viewColors[viewEnd + j] = 1;
    }
    viewEnd += 18;

    winTrianglesNum = 18;

    viewColors[viewEnd] = 1; view[viewEnd] =  -0.20; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] =  -0.2; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] = -0.02; viewEnd++;

    viewColors[viewEnd] = 1; view[viewEnd] =  -0.10; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] =  -0.1; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] = -0.02; viewEnd++;

    viewColors[viewEnd] = 1; view[viewEnd] =  0.10; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] =  -0.1; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] = -0.02; viewEnd++;

    viewColors[viewEnd] = 1; view[viewEnd] =  0.20; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] =  -0.2; viewEnd++;
    viewColors[viewEnd] = 1; view[viewEnd] = -0.02; viewEnd++;

    lineStripNum = 4;
}

//------------public functions-------------
GameInterface::GameInterface(Game *game) : game(game){
    squareSize = 0.1;
    selectionSize = 0.15;
    squareSpace = 0.15;

    viewChanged = true;
    endGame = true;

    viewEnd = game->getFields() * 18;
    trianglesNum = viewEnd / 3;
    winTrianglesNum = 0;
    lineStripNum = 0;

    selection = 0;

    reserveMemory();

    randColors();
}

void GameInterface::createDisplay(){
    boardUp();

    if(viewChanged) {
        createCheckBox();
        viewChanged = false;
    }

    if(game->isEnd() == 1 && endGame){
        cout << "end: 1" << endl;
        createPlayerWin();
        endGame = false;
    } else if(game->isEnd() == 2 && endGame){
        cout << "end: 2" << endl;
        createPlayerLoose();
        endGame = false;
    }
}

void GameInterface::addCheckToBoard(){
    if(game->getRound() < game->getRounds()){
        int fields = game->getFields();

        GLfloat *square = new GLfloat[18];

        float start = -1.0 + squareSpace/2.0 + squareSize/2.0;

        for(int i = 0; i < fields; i++){
            createSquare(start + squareSpace * i, start, 0, squareSize, square);

            for(int j = 0; j < 18; j++){
                view[viewEnd + i*18 + j] = square[j];
            }
        }

        for(int i = 0; i < fields*18; i++){
            viewColors[viewEnd + i] = viewColors[i];
        }

        viewEnd += fields * 18;
        trianglesNum = viewEnd / 3;
    }
}

void GameInterface::addReply(int *ans){
    if(game->getRound() < game->getRounds() && ans != NULL){
        int fields = game->getFields();

        GLfloat *square = new GLfloat[18];

        int blacks = 0;
        int whites = 0;

        for(int i = 0; i < fields; i++){
            if(ans[i] == 2) blacks++;
            if(ans[i] == 1) whites++;
        }

        float startx = -1.0 + squareSpace/2.0 + squareSize/2.0 + squareSpace * game->getFields();
        float starty = -1.0 + squareSpace/2.0 + squareSize/2.0;

        for(int i = 0; i < blacks; i++){
            createSquare(startx + squareSpace * i, starty, 0, squareSize, square);

            for(int j = 0; j < 18; j++){
                view[viewEnd + i*18 + j] = square[j];
                viewColors[viewEnd + i*18 + j] = 0;
            }
        }

        for(int i = blacks; i < blacks + whites; i++){
            createSquare(startx + squareSpace * i, starty, 0, squareSize, square);

            for(int j = 0; j < 18; j++){
                view[viewEnd + i*18 + j] = square[j];
                viewColors[viewEnd + i*18 + j] = 1;
            }
        }

        viewEnd += (blacks + whites) * 18;
        trianglesNum = viewEnd / 3;
    }
}

void GameInterface::boardUp(){
    int fields = game->getFields();

    float start = -1.0 + squareSpace/2.0 + squareSize;

    if(view[fields*18 + 1] < start + squareSpace * game->getRound()){
        for(int i = fields*18; i < trianglesNum*3; i++){
            if(i%3 == 1) view[i] += 0.01;
        }
    }
}

void GameInterface::interfaceReset(){
    viewEnd = game->getFields() * 18;

    selection = 0;

    winTrianglesNum = 0;
    lineStripNum = 0;

    randColors();

    for(int i = 0; i < game->getFields(); i++){
        checkBox[i] = 0;
    }

    viewChanged = true;
    endGame = true;
}

void GameInterface::selectNext(){
    if(selection < game->getFields() - 1) selection++;
    else selection = 0;

    viewChanged = true;
}
void GameInterface::selectPrev(){
    if(selection > 0) selection--;
    else selection = game->getFields() - 1;

    viewChanged = true;
}

void GameInterface::changeColor(int color){
    if(color < game->getColors()){
        checkBox[selection] = color;
    }

    viewChanged = true;
}

void GameInterface::colorNext(){
    if( checkBox[selection] < game->getColors() - 1 ) checkBox[selection]++;
    else checkBox[selection] = 0;

    viewChanged = true;
}

void GameInterface::colorPrev(){
    if( 0 < checkBox[selection] ) checkBox[selection]--;
    else checkBox[selection] = game->getColors() - 1;

    viewChanged = true;
}

//getters
float *GameInterface::getView(){
    return view;
}
float *GameInterface::getViewColors(){
    return viewColors;
}

int GameInterface::getViewSize(){
    return viewEnd;
}

int GameInterface::getTrianglesNum(){
    return trianglesNum;
}

int GameInterface::getWinTrianglesNum(){
    return winTrianglesNum;
}

int GameInterface::getLineStripNum(){
    return lineStripNum;
}

int *GameInterface::getCheckBox(){
    return checkBox;
}
